#include <opencv2/opencv.hpp>
#include <opencv2/dnn/dnn.hpp>
#include <iostream>
#include <dlib/dnn.h>
#include <dlib/gui_widgets.h>
#include <dlib/clustering.h>
#include <dlib/string.h>
#include <dlib/image_io.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/opencv.h>
#include <dirent.h>
#include <stdlib.h>
#include <vector>
using namespace std;
using namespace cv;
using namespace dlib;

void get_files(const std::string &path, std::vector<std::string> &label_files, std::vector<std::string> &label_names, std::string format)
{
    DIR *dp;
    struct dirent *dirp;
    const char *p = path.data();
    dp = opendir(p);

    while ((dirp = readdir(dp)) != NULL)
    {
        std::string filename = std::string(dirp->d_name);
        if (strcmp(filename.data(), ".") == 0 || strcmp(filename.data(), "..") == 0)
            continue;
        try
        {
            std::string file_suffix = filename.substr(filename.find_last_of("."));
            if (file_suffix.compare(format) == 0)
            {
                label_files.push_back(path + "/" + filename);
                label_names.push_back(filename);
            }
        }
        catch (const std::out_of_range &e)
        {
            std::cerr << "<---Abnormal data detected--->" << '\n';
        }
    }
    closedir(dp);
}

int main(int argc, char **argv)
{

    try
    {
        if (argc == 1)
        {
            cout << "Give some image files as arguments to this program." << endl;
            return 0;
        }

        frontal_face_detector detector = get_frontal_face_detector();
        image_window win;

        // Loop over all the images provided on the command line.

        std::vector<std::string> img_files;
        std::vector<std::string> img_names;
        std::string img_format = ".jpg";

        get_files(argv[1], img_files, img_names, img_format);

        // cv::namedWindow("faceDetect");
        for (int i = 0; i < img_files.size(); ++i)
        {

            cerr << "processing image " << img_names[i] << endl;
            // array2d<unsigned char> img;
            cv::Mat imgfile = cv::imread(samples::findFileOrKeep(img_files[i]), IMREAD_COLOR);

            // cv::imshow(img_names[i], imgfile);

            cv::Size s = imgfile.size();
            cerr << "w: " << s.width << "\th: " << s.height << endl;

            cv::Mat tmp = imgfile.clone();
            dlib::cv_image<dlib::bgr_pixel> img(tmp);

            double t = (double)getTickCount();

            std::vector<dlib::rectangle> dets = detector(img, 0);

            t = (double)getTickCount() - t;
            printf("detection time = %g ms\n", t * 1000 / getTickFrequency());
            cerr << "Number of faces detected: " << dets.size() << endl;

            // win.clear_overlay();
            // win.set_image(img);
            // win.add_overlay(dets, rgb_pixel(255,0,0));


            for (size_t i = 0; i < dets.size(); i++)
            {
                int x1 = dets[i].left();
                int y1 = dets[i].top();
                int x2 = dets[i].right();
                int y2 = dets[i].bottom();
                cv::rectangle(imgfile, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0));
            }

            imshow("faceDetect", imgfile);

            // dets.
            cerr << "Hit enter to process the next image..." << endl;
            cin.get();
        }
    }
    catch (exception &e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }

    cv::destroyAllWindows();
    return 0;
}
